Xsub()

External Subroutine Call

Syntax samples

XSUB(<file ID>, <ordinal function number> or <function name> {, <parameter1>, <parameter2>...})

XSUB(Interface,1, 5)

XSUB(LogDLL, "_Log_B_of_X",10,5)

Description

Calls an external subroutine inside a DLL file. XSUB() is perhaps the most powerful statement in ProModel, because by using it the user can access the entire functionality of any 32-bit Windows programming language such as C, C++, Delphi, or Visual Basic. XSUB() can be used for sophisticated file IO and to make simulations interactive. In fact, subroutines called with XSUB() can do anything that the language they were written in allows. Because of its power, however, XSUB() should be used with caution. When called, the simulation is suspended until the external subroutine finishes execution.

The subroutine inside the DLL must have been compiled as exportable by a Windows 32-bit compiler and have a return type of IEEE format double real. XSUB() will copy the parameters following the function name to a block of memory, then pass the function a pointer to that block of memory.

The function can take only one parameter: a pointer to void. But the function may access any number of parameters through structure overlaying. The function should define a structure to match the type and order of the parameters, and assign the pointer just passed to a pointer to that type of structure. The parameters can then be used through structure overlaying. Integers are passed as four byte values and reals are passed as eight byte IEEE values.

Please note

For Windows Programmers Only The handle to the run-time simulation frame window will be the last parameter passed. Most subroutines can completely ignore this parameter, but it will be needed if the subroutine displays a window.

Valid In

Any expression or logic.

Components

<file ID>

The file ID assigned to an external DLL file as defined in the External Files editor. This file should be a 32-bit Windows DLL file.

<ordinal function number>

The ordinal number of the function inside the DLL. This function must be exportable. When DLL’s are compiled, every exported function inside them is numbered. The individual functions can then be accessed by calling the program by number. This field may be an expression that evaluates to an ordinal function number that is valid inside the DLL. Use an ordinal function number or the function name.

<function name>

The name of the function inside the DLL. This function must be exportable. Note that when most compilers compile DLL’s, they adjust the name of the functions inside them. The function name inside the XSUB statement must be the adjusted name, not the original name.

Most C compilers add an underscore to the function name; so a function called "Test1" would be compiled as "_Test1." For most C++ compilers, valid ProModel external function names will be mangled to "@<function name>$pv." Different compilers will vary, however, so the user should be aware of the particular compiler’s quirks.

<parameters>

The parameters to pass to the function. These may be any variable, number, or expression. They are only limited by the type of field or logic that uses the XSUB function. Each parameter should be separated by a comma. See above for how the external subroutine will access these parameters.

Example

An external function written to the ProModel specification, called Log_B_of_X and written in C, returns the log of a value to a variable base. The function, reproduced below, has been compiled into the DLL, "XSUB.DLL." The function itself is reproduced on the left below, and the source code can be found in the file "XSUB.CPP."

The ProModel logic statements assign the base five logarithm of the real variable R1 to the real variable R2. Each statement assumes that the file XSUB.DLL has been assigned the identifier "Log" in the External Files Editor. The first statement accesses the function as if the DLL had been compiled in C++ by using the mangled function name. The second statement accesses the function as if it had been compiled in C by using the C adjusted function name. The third statement accesses the function using the ordinal function number.

ProModel Logic

R2 = XSUB(Log, "@Log_B_X$pv",5.0,R1)
R2 = XSUB(Log, "_Log_B_X",5.0,R1)
R2 = XSUB(Log, 2, 5.0, R1)

XSUB.CPP

struct TEST_SUB_PARAMS

{
double base;
double x;
HWND hWndFrame;
};

extern "C" //This makes this a C function rather than a C++ function
{
/* On compile, Borland and Microsoft add a leading underscore to a 'C' name! */
double _export Log_B_of_X(void *p)
{

//Parameters come in a structure pointed to by p;
TEST_SUB_PARAMS * params;
params = (TEST_SUB_PARAMS*) p;
MessageBox (GetTopWindow (params->hWndFrame),
"Executing Log_B_of_X function.", "XSUB", MB_OK);
return log (params->x) / log (params->base);
}
}

See Also

Subroutines (normal subroutines are less powerful, but much easier to create and use).